package com.cn.lp.openapi.aop;


import com.cn.lp.common.utils.BlankAide;
import com.cn.lp.openapi.base.OpenApiClientConstants;
import feign.Request;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.util.Collection;
import java.util.Map;

/**
 * @author qirong
 * @date 2019/4/3
 */
@Aspect
public class FeignClientAOP implements EnvironmentAware {

    private Environment environment;

    /**
     * 此处的切点是注解的方式，也可以用包名的方式达到相同的效果
     * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
     */
    @Pointcut("execution(* org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(feign.Request, feign.Request.Options))")
    public void cutExecute() {

    }

    @Pointcut("execution(* org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.getDelegate())")
    public void cutDelegate() {

    }

    /**
     * 环绕增强，相当于MethodInterceptor
     */
    @Around("cutDelegate()")
    public Object doAroundDelegate(ProceedingJoinPoint joinPoint) throws Throwable {
        return new FeignClientProxy((LoadBalancerFeignClient) joinPoint.getTarget(), environment);
    }

    /**
     * 环绕增强，相当于MethodInterceptor
     */
    @Around("cutExecute()")
    public Object doAroundExecute(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        if(target instanceof LoadBalancerFeignClient) {
            Object[] args = joinPoint.getArgs();
            if(args != null && args.length > 1) {
                Request request = (Request) args[0];
                Request.Options options = (Request.Options) args[1];
                Map<String, Collection<String>> headers = request.headers();
                if(BlankAide.isNotBlank(headers)) {
                    Collection<String> dynUrlKeys = headers.get(OpenApiClientConstants.DYN_URL);
                    if (BlankAide.isNotBlank(dynUrlKeys)) {
                        String dynUrlKey = dynUrlKeys.stream().findFirst().get();
                        String dynUrl = environment.getProperty(dynUrlKey);
                        if(BlankAide.isNotBlank(dynUrl)) {
                            LoadBalancerFeignClient loadBalancerFeignClient = (LoadBalancerFeignClient)target;
                            return loadBalancerFeignClient.getDelegate().execute(request, options);
                        }
                    }
                }
            }
        }
        return joinPoint.proceed();
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
